package psmanager.db;

import java.io.File;
import java.util.List;

import psmanager.db.types.Cuvar;
import psmanager.db.types.Doktor;
import psmanager.db.types.KriminalnaRadnja;
import psmanager.db.types.Osoba;
import psmanager.db.types.Pljacka;
import psmanager.db.types.PrometniPrekrsaj;
import psmanager.db.types.Silovanje;
import psmanager.db.types.Ubojstvo;
import psmanager.db.types.Zatvorenik;

import com.db4o.Db4o;
import com.db4o.ObjectContainer;
import com.db4o.query.Candidate;
import com.db4o.query.Evaluation;
import com.db4o.query.Predicate;
import com.db4o.query.Query;

public class DBManager {

	private ObjectContainer storeDB;

	private static long id;

	public DBManager() {
		id = 0;
		new File("./db/store.db").delete();
		storeDB = Db4o.openFile("./db/store.db");
	}

	public void cleanUp() {
		storeDB.close();
	}

	@Override
	protected void finalize() throws Throwable {
		storeDB.close();
		super.finalize();
	}

	public static long generateId() {
		return ++id;
	}

	public List<?> grabAllByClass(Class<?> classToGrab) {
		Query query = storeDB.query();
		query.constrain(classToGrab);
		return query.execute();
	}

	public List<Osoba> grabPersonsByQBE(Osoba proto) {
		return storeDB.queryByExample(proto);
	}

	public List<Osoba> grabOsobeByAtrributes(final String jmbg,
			final String tip, final String ime, final String prezime,
			final String adresa, final int dob) {
		return storeDB.query(new Predicate<Osoba>() {
			private static final long serialVersionUID = 1545454L;

			@Override
			public boolean match(Osoba osoba) {
				boolean tipFlag = true;
				if (!tip.equals("Svi")) {
					if (tip.equals("Zatvorenik")
							&& !(osoba instanceof Zatvorenik))
						tipFlag = false;
					else if (tip.equals("Čuvar") && !(osoba instanceof Cuvar))
						tipFlag = false;
					else if (tip.equals("Doktor") && !(osoba instanceof Doktor))
						tipFlag = false;
				}

				if ((jmbg == null || osoba.getJmbg().contains(jmbg))
						&& tipFlag
						&& (ime == null || osoba.getIme().contains(ime))
						&& (prezime == null || osoba.getPrezime().contains(
								prezime))
						&& (adresa == null || osoba.getPrebivaliste()
								.toString().contains(adresa))
						&& (dob == -1 || osoba.calculateAge() == dob))
					return true;
				else
					return false;
			}
		});
	}

	@SuppressWarnings({ "serial", "unchecked" })
	public List<Osoba> grabOsobeByAtrributesSorted(final String jmbg,
			final String tip, final String ime, final String prezime,
			final String adresa, final int dob, String orderBy, boolean orderAscending) {

		Query query = storeDB.query();
		
		if(tip.equals("Svi")) {
			query.constrain(Osoba.class);
		} else if(tip.equals("Zatvorenik")) {
			query.constrain(Zatvorenik.class);
		} else if(tip.equals("Čuvar")) {
			query.constrain(Cuvar.class);
		} else {
			query.constrain(Doktor.class);
		}
		
		query.constrain(new Evaluation() {
			@Override
			public void evaluate(Candidate candidate) {
				Osoba osoba = (Osoba) candidate.getObject();
				
				candidate.include((jmbg == null || osoba.getJmbg().contains(jmbg)) && 
						(ime == null || osoba.getIme().contains(ime)) && 
						(prezime == null || osoba.getPrezime().contains(prezime)) && 
						(adresa == null || osoba.getPrebivaliste().toString().contains(adresa)) && 
						(dob == -1 || osoba.calculateAge() == dob));
			}
		});
		
		if(!orderBy.equals("Nesortirano")) {
			if(orderAscending) {
				if(orderBy.equals("JMBG")) query.descend("jmbg").orderAscending();
				if(orderBy.equals("Ime")) query.descend("ime").orderAscending();
				if(orderBy.equals("Prezime")) query.descend("prezime").orderAscending();
				if(orderBy.equals("Adresa")) query.descend("prebivaliste").
							descend("mjesto").descend("naziv").orderAscending();
				if(orderBy.equals("Dob")) query.descend("rodjen").orderAscending();
			} else {
				if(orderBy.equals("JMBG")) query.descend("jmbg").orderDescending();
				if(orderBy.equals("Ime")) query.descend("ime").orderDescending();
				if(orderBy.equals("Prezime")) query.descend("prezime").orderDescending();
				if(orderBy.equals("Adresa")) query.descend("prebivaliste").
							descend("mjesto").descend("naziv").orderDescending();
				if(orderBy.equals("Dob")) query.descend("rodjen").orderDescending();
			}
		}

		return query.execute();
	}

	public List<Zatvorenik> grabAllCriminalsByRecord(
			final KriminalnaRadnja kRadnja) {
		return storeDB.query(new Predicate<Zatvorenik>() {
			private static final long serialVersionUID = 1L;

			public boolean match(Zatvorenik zat) {
				if (zat.getDosje() == null)
					return false;
				for (KriminalnaRadnja kr : zat.getDosje().getPrijestupi()) {
					if (kRadnja instanceof Ubojstvo)
						if (kr instanceof Ubojstvo)
							return true;
						else if (kRadnja instanceof Pljacka)
							if (kr instanceof Pljacka)
								return true;
							else if (kRadnja instanceof Silovanje)
								if (kr instanceof Silovanje)
									return true;
								else if (kRadnja instanceof PrometniPrekrsaj)
									if (kr instanceof PrometniPrekrsaj)
										return true;
				}
				return false;
			}
		});
	}

	public boolean store(Object obj) {
		storeDB.store(obj);
		return true;
	}

	public boolean deleteOsoba(String jmbg) {

		Osoba osobaProto = new Osoba(jmbg);
		List<Osoba> listOsoba = storeDB.queryByExample(osobaProto);

		if (listOsoba.size() == 0)
			return false;

		Osoba osoba = listOsoba.get(0);

		storeDB.delete(osoba);

		return true;
	}
	

}
